package com.hyperfix.common.handler;

import com.hyperfix.common.exception.CustomException;
import com.hyperfix.common.service.MailService;
import com.hyperfix.models.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * @author JiangChunYu
 * 2024/4/5
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @Resource
    private MailService mailService;

    @Resource
    private HttpServletRequest httpServletRequest;
    /**
     * 业务异常
     *
     * @param e 捕获CustomException异常
     * @return 错误信息
     */
    @ExceptionHandler(value = CustomException.class)
    public R<String> handleCustomException(CustomException e) {
        final String errMsg = e.getMessage();
        log.error(errMsg);
        return R.error(errMsg);
    }

    /**
     * 参数为实体类的校验异常
     *
     * @param e 捕获MethodArgumentNotValidException异常
     * @return 错误信息
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R<String> handleValidException(MethodArgumentNotValidException e) {
        // 从异常对象中拿到ObjectError对象
        final String errMsg = e.getBindingResult().getAllErrors().stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.joining("<br/>"));
        log.error(errMsg);
        // 然后提取错误提示信息进行返回
        return R.error(errMsg);
    }

    /**
     * 参数为单个参数或多个参数的校验异常
     *
     * @param e 捕获MethodArgumentNotValidException异常
     * @return 错误信息
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public R<String> handleConstraintViolationException(ConstraintViolationException e) {
        final String errMsg = e.getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining("<br/>"));
        log.error(errMsg);
        return R.error(errMsg);
    }

    /**
     * 未知异常
     *
     * @param e 捕获Exception异常
     * @return 错误信息
     */
    @ExceptionHandler(value = Exception.class)
    public R<String> handleException(Exception e) {
        final String errMsg = e.getMessage();
        log.error(errMsg);
        // 发送邮件给开发者
        String stackTrace = Arrays.toString(e.getStackTrace());
        mailService.sendEmailToDeveloper(
                httpServletRequest.getRemoteAddr(),
                httpServletRequest.getRequestURI(),
                errMsg,
                stackTrace
        );
        return R.error("未知错误！");
    }
}
